package com.xpxrule.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.xpxrule.constant.Operator;
import com.xpxrule.dataobject.biz.model.ReturnResponse;
import com.xpxrule.dataobject.dao.Rule;
import com.xpxrule.dataobject.req.RuleQueryReq;
import com.xpxrule.dataobject.vo.OptionVo;
import com.xpxrule.dataobject.vo.RuleDisplayVo;
import com.xpxrule.dataobject.vo.RuleVo;
import com.xpxrule.mapper.RuleMapper;
import com.xpxrule.service.RuleService;
import com.xpxrule.util.FieldDisplayUtil;
import com.xpxrule.util.ModelConvertUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @version 1.0
 * @Author xiangpengxiang
 * @Date 2024/12/9 15:43
 * @注释
 */
@Service
public class RuleServiceImpl implements RuleService {
    @Autowired
    private RuleMapper ruleMapper;
    @Autowired
    private FieldDisplayUtil fieldDisplayUtil;

    @Override
    public ReturnResponse insert(RuleVo vo) {
        boolean isExist = verifyDbUnique(vo);
        if (!isExist) {
            return ReturnResponse.fail("The unique verification failed. The new data already exists in the database.");
        }
        Rule dao = ModelConvertUtil.convertRuleVoToRule(vo);
        int count = ruleMapper.insert(dao);
        return ReturnResponse.success(count);
    }

    @Override
    public ReturnResponse delete(Long id) {
        // 存在性校验
        boolean isExist = verifyDbExistById(id);
        if (!isExist) {
            return ReturnResponse.fail("The data does not exist in the database.");
        }
        Rule rule = ruleMapper.selectById(id);
        rule.setIsDeleted(new Date());
        int count = ruleMapper.updateById(rule);
        return ReturnResponse.success(count);
    }

    @Override
    public ReturnResponse update(RuleVo vo) {
        boolean isExist = verifyDbExistById(Long.valueOf(vo.getId()));
        if (!isExist) {
            return ReturnResponse.fail("The data does not exist in the database.");
        }
        Rule old = ruleMapper.selectById(vo.getId());
        ModelConvertUtil.fillRuleFromRuleVo(old, vo);
        int count = ruleMapper.updateById(old);
        return ReturnResponse.success(count);
    }

    @Override
    public List<Rule> selectRuleListByRuleScenarios(String ruleScenariosKey) {
        QueryWrapper<Rule> wrapper = new QueryWrapper<>();
        wrapper.eq(Rule.COLUMN.SCENARIOS_KEY, ruleScenariosKey);
        wrapper.isNull(Rule.COLUMN.IS_DELETED);
        wrapper.eq(Rule.COLUMN.IS_ENABLE, 0);
        List<Rule> rules = ruleMapper.selectList(wrapper);
        return rules;
    }

    @Override
    public ReturnResponse<List<RuleVo>> selectList(RuleQueryReq req) {
        List<Rule> list = selectRuleListByQueryParam(req);
        List<RuleVo> resultList = list.stream()
                .map(ModelConvertUtil::convertRuleToRuleVo)
                .collect(Collectors.toList());
        return new ReturnResponse<>(resultList);
    }

    private List<Rule> selectRuleListByQueryParam(RuleQueryReq req) {
        QueryWrapper<Rule> wrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(req.getScenariosKey())) {
            wrapper.eq(Rule.COLUMN.SCENARIOS_KEY, req.getScenariosKey());
        }
        if (!StringUtils.isEmpty(req.getRuleName())) {
            wrapper.like(Rule.COLUMN.RULE_NAME, req.getRuleName());
        }
        if (!ObjectUtils.isEmpty(req.getIsEnable())) {
            wrapper.eq(Rule.COLUMN.IS_ENABLE, req.getIsEnable());
        }
        wrapper.isNull(Rule.COLUMN.IS_DELETED);
        List<Rule> list = ruleMapper.selectList(wrapper);
        return list;
    }

    @Override
    public ReturnResponse<List<OptionVo>> getAllOperator() {
        List<OptionVo> resultList = new ArrayList<>();
        for (Operator operator : Operator.values()) {
            OptionVo optionVo = new OptionVo();
            optionVo.setKey(operator.getCode());
            optionVo.setValue(operator.getZhName());
            resultList.add(optionVo);
        }
        return new ReturnResponse<>(resultList);
    }

    @Override
    public Rule selectRuleByScenariosAndRuleName(String scenariosKey, String ruleName) {
        QueryWrapper<Rule> wrapper = new QueryWrapper<>();
        wrapper.eq(Rule.COLUMN.SCENARIOS_KEY, scenariosKey);
        wrapper.eq(Rule.COLUMN.RULE_NAME, ruleName);
        wrapper.isNull(Rule.COLUMN.IS_DELETED);
        List<Rule> ruleList = ruleMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(ruleList) || ruleList.size() != 1) {
            throw new RuntimeException("The data does not exist in the database.");
        }
        return ruleList.get(0);
    }

    @Override
    public ReturnResponse<List<RuleDisplayVo>> selectRuleDisplayList(RuleQueryReq req) {
        List<Rule> ruleList = selectRuleListByQueryParam(req);
        List<RuleDisplayVo> resultList = new ArrayList<>();
        for (Rule rule : ruleList) {
            RuleDisplayVo ruleDisplayVo = fieldDisplayUtil.convertRuleToRuleDisplayVo(rule);
            resultList.add(ruleDisplayVo);
        }
        return new ReturnResponse<>(resultList);
    }

    /**
     * 校验数据库是否存在该数据
     * @param id
     * @return
     */
    private boolean verifyDbExistById(Long id) {
        QueryWrapper<Rule> wrapper = new QueryWrapper<>();
        wrapper.eq(Rule.COLUMN.ID, id);
        wrapper.isNull(Rule.COLUMN.IS_DELETED);
        Long count = ruleMapper.selectCount(wrapper);
        return count == 1;
    }

    /**
     * 校验数据库唯一性
     * @param vo
     * @return
     */
    private boolean verifyDbUnique(RuleVo vo) {
        QueryWrapper<Rule> wrapper = new QueryWrapper<>();
        wrapper.eq(Rule.COLUMN.SCENARIOS_KEY, vo.getScenariosKey());
        wrapper.eq(Rule.COLUMN.RULE_NAME, vo.getRuleName());
        wrapper.isNull(Rule.COLUMN.IS_DELETED);
        Long count = ruleMapper.selectCount(wrapper);
        return count == 0;
    }
}
